﻿//  Copyright (c) 2011 Ray Liang (http://www.dotnetage.com)
//  Licensed MIT: http://www.opensource.org/licenses/mit-license.php

using System.Collections.Generic;
using System.Data.Entity;
using System.IO;
using System;

namespace DNA.Mvc.Installation
{
    public class SqlScriptInstaller : InstallerBase
    {
        public override string Name
        {
            get { return "sql"; }
        }

        public override void Execute(InstallationContext context)
        {
            var config = GetConfig<SqlScriptConfiguration>();

            if (!string.IsNullOrEmpty(config.ScriptFileName))
            {
                string tmplFile = ExecutionPath + "\\" + config.ScriptFileName;
                if (!File.Exists(tmplFile)) throw new Exception("Sql file not exists");

                string sqlTextBlock = File.ReadAllText(tmplFile);

                var cmds = ReadSQLCommandBlocksFromText(sqlTextBlock);

                if (cmds.Length > 0)
                {
                    if (config.Replacements != null)
                    {
                        foreach (var match in config.Replacements)
                        {
                            if (context.Data.ContainsKey(match.Value))
                            {
                                var _val = context.Data[match.Value] as string;
                                if (!string.IsNullOrEmpty(_val))
                                {
                                    for (int i = 0; i < cmds.Length; i++)
                                    {
                                        if (cmds[i].IndexOf(match.Match) > -1)
                                            cmds[i] = cmds[i].Replace(match.Match, RemoveRiskChars(_val));
                                    }
                                }
                            }
                        }
                    }

                    context.Trace.Write(string.Format("Preparing {0} lines sql command to execute.", cmds.Length));

                    using (var db = new DbContext(config.ConnectionStringName))
                    {
                        try
                        {
                            foreach (var cmd in cmds)
                            {
                                db.Database.ExecuteSqlCommand(cmd);
                            }
                        }
                        catch (Exception e)
                        {
                            context.Trace.Warn("Error", e.Message, e);
                        }
                    }

                    context.Trace.Write(string.Format("Install sql script success. Totoal {0} sql command lines has been executed.", cmds.Length));

                }
            }
        }

        private string RemoveRiskChars(string raw)
        {
            string s = "";
            s = raw.Replace("'", "''");
            s = s.Replace(";", " ");
            s = s.Replace("1=1", " ");
            s = s.Replace("|", " ");
            s = s.Replace("<", " ");
            s = s.Replace(">", " ");

            return s;
        }

        /// <summary>
        /// Read the SQL command blocks into string array
        /// </summary>
        /// <param name="text">Specified the sql script text.</param>
        /// <returns>The sql command block string array.</returns>
        private string[] ReadSQLCommandBlocksFromText(string text)
        {
            var reader = new StringReader(text);
            return ReadSQLCommandBlocksFromReader(reader);
        }

        /// <summary>
        /// Read the SQL command blocks into string array
        /// </summary>
        /// <param name="reader"></param>
        /// <returns>The sql command block string array</returns>
        private string[] ReadSQLCommandBlocksFromReader(TextReader reader)
        {
            return ReadSQLCommandBlocksFromReader(reader, string.Empty, string.Empty);
        }

        /// <summary>
        /// Read the SQL command blocks into string array
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="pattern"></param>
        /// <param name="replacement"></param>
        /// <returns>The sql command block string array</returns>
        private string[] ReadSQLCommandBlocksFromReader(TextReader reader, string pattern, string replacement)
        {
            var sqls = new List<string>();
            string commandText = "";
            string varLine = "";

            while (reader.Peek() > -1)
            {
                varLine = reader.ReadLine();
                if (varLine == "")
                    continue;

                if (varLine.Trim().StartsWith("--"))
                    continue;

                if (!varLine.Trim().Equals("GO", StringComparison.OrdinalIgnoreCase))
                {
                    commandText += varLine;
                    commandText += " ";
                }
                else
                {
                    if ((!string.IsNullOrEmpty(pattern)) && (!string.IsNullOrEmpty(replacement)))
                    {
                        if (commandText.IndexOf(pattern) > -1)
                            commandText.Replace(pattern, replacement);
                    }
                    sqls.Add(commandText);
                    commandText = "";
                }
            }
            reader.Close();
            return sqls.ToArray();
        }
    }

}
